<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 2.0.26">
<link rel="icon" type="image/svg" href="../../../../_docs/_Assets/Logo.svg">
<title>Basic ViewLocator Sample</title>
<style>
@import url(https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css);

:root {
    --background: #fff;
    --black-color: #000;
    --background-yellow: #ff0;
    --border: #c0c0c0;
    --gray-color: #6c818f;
    --link-color-default: var(--accent-primary-color);
    --foreground-color: #222222;
    --accent-primary-color: #3578e5;
    --accent-secondary-color: #102445;
    --border2: #dddddd;
    --block-quote-color: #748590;
    --pre-background-color: #f2f2f2;
    --dark-gray-color: #333333;
    --kdb-background-color: #F7F7F7;
    --header-color: var(--accent-primary-color);
    --link-hover-color: #102445;
    --toc-border-color: #d9d9d9;
    --exampleblock-border-color: #e6e6e6;
    --em-color: #373737;
    --admotion-background-color: #e6e6e6;
    --sidebar-background-color: #e8ecef;
    --border-radius-default: 6px;
}

/* normalize.css v2.1.1 | MIT License | git.io/normalize */
/* ========================================================================== HTML5 display definitions ========================================================================== */
/** Correct `block` display not defined in IE 8/9. */
article, aside, details, figcaption, figure, footer, header, hgroup, main, nav, section, summary {
    display: block;
}

/** Correct `inline-block` display not defined in IE 8/9. */
audio, canvas, video {
    display: inline-block;
}

/** Prevent modern browsers from displaying `audio` without controls. Remove excess height in iOS 5 devices. */
audio:not([controls]) {
    display: none;
    height: 0;
}

/** Address styling not present in IE 8/9. */
[hidden] {
    display: none;
}

/* ========================================================================== Base ========================================================================== */
/** 1. Prevent system color scheme's background color being used in Firefox, IE, and Opera. 2. Prevent system color scheme's text color being used in Firefox, IE, and Opera. 3. Set default font family to sans-serif. 4. Prevent iOS text size adjust after orientation change, without disabling user zoom. */
html {
    background: var(--background); /* 1 */
    color: var(--black-color); /* 2 */
    font-family: sans-serif; /* 3 */
    -ms-text-size-adjust: 100%; /* 4 */
    -webkit-text-size-adjust: 100%; /* 4 */
}

/** Remove default margin. */
body {
    margin: 0;
}

/* ========================================================================== Links ========================================================================== */
/** Address `outline` inconsistency between Chrome and other browsers. */
a:focus {
    outline: thin dotted;
}

/** Improve readability when focused and also mouse hovered in all browsers. */
a:active, a:hover {
    outline: 0;
}

/* ========================================================================== Typography ========================================================================== */
/** Address variable `h1` font-size and margin within `section` and `article` contexts in Firefox 4+, Safari 5, and Chrome. */
h1 {
    font-size: 2em;
    margin: 0.67em 0;
}

/** Address styling not present in IE 8/9, Safari 5, and Chrome. */
abbr[title] {
    border-bottom: 1px dotted;
}

/** Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome. */
b, strong {
    font-weight: bold;
}

/** Address styling not present in Safari 5 and Chrome. */
dfn {
    font-style: italic;
}

/** Address differences between Firefox and other browsers. */
hr {
    -moz-box-sizing: content-box;
    box-sizing: content-box;
    height: 0;
}

/** Address styling not present in IE 8/9. */
mark {
    background: var(--background-yellow);
    color: var(--black-color);
}

/** Correct font family set oddly in Safari 5 and Chrome. */
code, kbd, pre, samp {
    font-family: monospace, serif;
    font-size: 1em;
}

/** Improve readability of pre-formatted text in all browsers. */
pre {
    white-space: pre-wrap;
}

/** Set consistent quote types. */
q {
    quotes: "\201C" "\201D" "\2018" "\2019";
}

/** Address inconsistent and variable font size in all browsers. */
small {
    font-size: 80%;
}

/** Prevent `sub` and `sup` affecting `line-height` in all browsers. */
sub, sup {
    font-size: 75%;
    line-height: 0;
    position: relative;
    vertical-align: baseline;
}

sup {
    top: -0.5em;
}

sub {
    bottom: -0.25em;
}

/* ========================================================================== Embedded content ========================================================================== */
/** Remove border when inside `a` element in IE 8/9. */
img {
    border: 0;
}

/** Correct overflow displayed oddly in IE 9. */
svg:not(:root) {
    overflow: hidden;
}

/* ========================================================================== Figures ========================================================================== */
/** Address margin not present in IE 8/9 and Safari 5. */
figure {
    margin: 0;
}

/* ========================================================================== Forms ========================================================================== */
/** Define consistent border, margin, and padding. */
fieldset {
    border: 1px solid var(--border);
    margin: 0 2px;
    padding: 0.35em 0.625em 0.75em;
}

/** 1. Correct `color` not being inherited in IE 8/9. 2. Remove padding so people aren't caught out if they zero out fieldsets. */
legend {
    border: 0; /* 1 */
    padding: 0; /* 2 */
}

/** 1. Correct font family not being inherited in all browsers. 2. Correct font size not being inherited in all browsers. 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome. */
button, input, select, textarea {
    font-family: inherit; /* 1 */
    font-size: 100%; /* 2 */
    margin: 0; /* 3 */
}

/** Address Firefox 4+ setting `line-height` on `input` using `!important` in the UA stylesheet. */
button, input {
    line-height: normal;
}

/** Address inconsistent `text-transform` inheritance for `button` and `select`. All other form control elements do not inherit `text-transform` values. Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+. Correct `select` style inheritance in Firefox 4+ and Opera. */
button, select {
    text-transform: none;
}

/** 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` and `video` controls. 2. Correct inability to style clickable `input` types in iOS. 3. Improve usability and consistency of cursor style between image-type `input` and others. */
button, html input[type="button"], input[type="reset"], input[type="submit"] {
    -webkit-appearance: button; /* 2 */
    cursor: pointer; /* 3 */
}

/** Re-set default cursor for disabled elements. */
button[disabled], html input[disabled] {
    cursor: default;
}

/** 1. Address box sizing set to `content-box` in IE 8/9. 2. Remove excess padding in IE 8/9. */
input[type="checkbox"], input[type="radio"] {
    box-sizing: border-box; /* 1 */
    padding: 0; /* 2 */
}

/** 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome. 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome (include `-moz` to future-proof). */
input[type="search"] {
    -webkit-appearance: textfield; /* 1 */
    -moz-box-sizing: content-box;
    -webkit-box-sizing: content-box; /* 2 */
    box-sizing: content-box;
}

/** Remove inner padding and search cancel button in Safari 5 and Chrome on OS X. */
input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration {
    -webkit-appearance: none;
}

/** Remove inner padding and border in Firefox 4+. */
button::-moz-focus-inner, input::-moz-focus-inner {
    border: 0;
    padding: 0;
}

/** 1. Remove default vertical scrollbar in IE 8/9. 2. Improve readability and alignment in all browsers. */
textarea {
    overflow: auto; /* 1 */
    vertical-align: top; /* 2 */
}

/* ========================================================================== Tables ========================================================================== */
/** Remove most spacing between table cells. */
table {
    border-collapse: collapse;
    border-spacing: 0;
}

*, *:before, *:after {
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
}

html, body {
    font-size: 100%;
}

body {
    background: white;
    color: var(--foreground-color);
    padding: 0;
    margin: 0;
    font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif;
    font-weight: normal;
    font-style: normal;
    line-height: 1;
    position: relative;
    cursor: auto;
}

a:hover {
    cursor: pointer;
}

a:focus {
    outline: none;
}

img, object, embed {
    max-width: 100%;
    height: auto;
}

object, embed {
    height: 100%;
}

img {
    -ms-interpolation-mode: bicubic;
}

#map_canvas img, #map_canvas embed, #map_canvas object, .map_canvas img, .map_canvas embed, .map_canvas object {
    max-width: none !important;
}

.left {
    float: left !important;
}

.right {
    float: right !important;
}

.text-left {
    text-align: left !important;
}

.text-right {
    text-align: right !important;
}

.text-center {
    text-align: center !important;
}

.text-justify {
    text-align: justify !important;
}

.hide {
    display: none;
}

.antialiased, body {
    -webkit-font-smoothing: antialiased;
}

img {
    display: inline-block;
    vertical-align: middle;
}

textarea {
    height: auto;
    min-height: 50px;
}

select {
    width: 100%;
}

p.lead, .paragraph.lead > p, #preamble > .sectionbody > .paragraph:first-of-type p {
    font-size: 1.21875em;
    line-height: 1.6;
}

.subheader, #content #toctitle, .admonitionblock td.content > .title, .exampleblock > .title, .imageblock > .title, .videoblock > .title, .listingblock > .title, .literalblock > .title, .openblock > .title, .paragraph > .title, .quoteblock > .title, .sidebarblock > .title, .tableblock > .title, .verseblock > .title, .dlist > .title, .olist > .title, .ulist > .title, .qlist > .title, .hdlist > .title, .tableblock > caption {
    line-height: 1.4;
    color: var(--accent-primary-color);
    font-weight: 300;
    margin-top: 0.5em;
    margin-bottom: 0.5em;
}

/* Typography resets */
div, dl, dt, dd, ul, ol, li, h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6, pre, form, p, blockquote, th, td {
    margin: 0;
    /*padding: 0;*/
    direction: ltr;
}

/* Default Link Styles */
a {
    color: var(--link-color-default);
    text-decoration: none;
    line-height: inherit;
}

a:hover, a:focus {
    color: var(--header-color);
}

a img {
    border: none;
}

/* Default paragraph styles */
p {
    font-family: inherit;
    font-weight: normal;
    font-size: 1em;
    line-height: 1.5;
    margin-bottom: 1.25em;
    text-rendering: optimizeLegibility;
}

p aside {
    font-size: 0.875em;
    line-height: 1.35;
    font-style: italic;
}

/* Default header styles */
h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 {
    font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, "Helvetica Neue", sans-serif;
    font-weight: bold;
    font-style: normal;
    color: var(--accent-primary-color);
    text-rendering: optimizeLegibility;
    margin-top: 1em;
    margin-bottom: 0.5em;
    line-height: 1.2125em;
}

h1 small, h2 small, h3 small, #toctitle small, .sidebarblock > .content > .title small, h4 small, h5 small, h6 small {
    font-size: 60%;
    color: var(--accent-secondary-color);
    line-height: 0;
}

h1 {
    font-size: 2.125em;
}

h2 {
    font-size: 1.6875em;
}

h3, #toctitle, .sidebarblock > .content > .title {
    font-size: 1.375em;
}

h4 {
    font-size: 1.125em;
}

h5 {
    font-size: 1.125em;
}

h6 {
    font-size: 1em;
}

hr {
    border: solid var(--border2);
    border-width: 1px 0 0;
    clear: both;
    margin: 1.25em 0 1.1875em;
    height: 0;
}

/* Helpful Typography Defaults */
em, i {
    font-style: italic;
    line-height: inherit;
}

strong, b {
    font-weight: bold;
    line-height: inherit;
}

small {
    font-size: 60%;
    line-height: inherit;
}

code {
    font-family: "Consolas", "Deja Vu Sans Mono", "Bitstream Vera Sans Mono", monospace;
    font-weight: normal;
    color: var(--link-color-default);
}

/* Lists */
ul, ol, dl {
    font-size: 1em;
    line-height: 1.5;
    margin-bottom: 1.25em;
    list-style-position: outside;
    font-family: inherit;
}

ul, ol {
    margin-left: 0;
}

/* Unordered Lists */
ul li ul, ul li ol {
    margin-left: 1.25em;
    margin-bottom: 0;
    font-size: 1em; /* Override nested font-size change */
}

ul.square li ul, ul.circle li ul, ul.disc li ul {
    list-style: inherit;
}

ul.square {
    list-style-type: square;
}

ul.circle {
    list-style-type: circle;
}

ul.disc {
    list-style-type: disc;
}

ul.no-bullet {
    list-style: none;
}

/* Ordered Lists */
ol li ul, ol li ol {
    margin-left: 1.25em;
    margin-bottom: 0;
}

/* Definition Lists */
dl dt {
    margin-bottom: 0.3em;
    font-weight: bold;
}

dl dd {
    margin-bottom: 0.75em;
}

/* Abbreviations */
abbr, acronym {
    text-transform: uppercase;
    font-size: 90%;
    color: black;
    border-bottom: 1px dotted var(--border2);
    cursor: help;
}

abbr {
    text-transform: none;
}

/* Blockquotes */
blockquote {
    margin: 0 0 1.25em;
    padding: 0.5625em 1.25em 0 1.1875em;
    border-left: 1px solid var(--border2);
}

blockquote cite {
    display: block;
    font-size: 0.8125em;
    color: var(--block-quote-color);
}

blockquote cite:before {
    content: "\2014 \0020";
}

blockquote cite a, blockquote cite a:visited {
    color: var(--block-quote-color);
}

blockquote, blockquote p {
    line-height: 1.5;
    color: var(--accent-secondary-color);
}

/* Microformats */
.vcard {
    display: inline-block;
    margin: 0 0 1.25em 0;
    border: 1px solid var(--border2);
    padding: 0.625em 0.75em;
}

.vcard li {
    margin: 0;
    display: block;
}

.vcard .fn {
    font-weight: bold;
    font-size: 0.9375em;
}

.vevent .summary {
    font-weight: bold;
}

.vevent abbr {
    cursor: auto;
    text-decoration: none;
    font-weight: bold;
    border: none;
    padding: 0 0.0625em;
}

@media only screen and (min-width: 768px) {
    h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 {
        line-height: 1.4;
    }

    h1 {
        font-size: 2.75em;
    }

    h2 {
        font-size: 2.3125em;
    }

    h3, #toctitle, .sidebarblock > .content > .title {
        font-size: 1.6875em;
    }

    h4 {
        font-size: 1.4375em;
    }
}

/* Print styles.  Inlined to avoid required HTTP connection: www.phpied.com/delay-loading-your-print-css/ Credit to Paul Irish and HTML5 Boilerplate (html5boilerplate.com)
*/
.print-only {
    display: none !important;
}

@media print {
    * {
        background: transparent !important;
        color: var(--black-color) !important; /* Black prints faster: h5bp.com/s */
        box-shadow: none !important;
        text-shadow: none !important;
    }

    a, a:visited {
        text-decoration: underline;
    }

    a[href]:after {
        content: " (" attr(href) ")";
    }

    abbr[title]:after {
        content: " (" attr(title) ")";
    }

    .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after {
        content: "";
    }

    pre, blockquote {
        border: 1px solid #999;
        page-break-inside: avoid;
    }

    thead {
        display: table-header-group; /* h5bp.com/t */
    }

    tr, img {
        page-break-inside: avoid;
    }

    img {
        max-width: 100% !important;
    }

    @page {
        margin: 0.5cm;
    }

    p, h2, h3, #toctitle, .sidebarblock > .content > .title {
        orphans: 3;
        widows: 3;
    }

    h2, h3, #toctitle, .sidebarblock > .content > .title {
        page-break-after: avoid;
    }

    .hide-on-print {
        display: none !important;
    }

    .print-only {
        display: block !important;
    }

    .hide-for-print {
        display: none !important;
    }

    .show-for-print {
        display: inherit !important;
    }
}

/* Tables */
table {
    background: white;
    margin-bottom: 1.25em;
    border: solid 0 var(--border2);
}

table thead, table tfoot {
    background: none;
    font-weight: bold;
}

table thead tr th, table thead tr td, table tfoot tr th, table tfoot tr td {
    padding: 1px 8px 1px 5px;
    font-size: 1em;
    color: var(--foreground-color);
    text-align: left;
}

table tr th, table tr td {
    padding: 1px 8px 1px 5px;
    font-size: 1em;
    color: var(--foreground-color);
}

table tr.even, table tr.alt, table tr:nth-of-type(even) {
    background: none;
}

table thead tr th, table tfoot tr th, table tbody tr td, table tr td, table tfoot tr td {
    display: table-cell;
    line-height: 1.5;
}

.clearfix:before, .clearfix:after, .float-group:before, .float-group:after {
    content: " ";
    display: table;
}

.clearfix:after, .float-group:after {
    clear: both;
}

*:not(pre) > code {
    font-size: 0.95em;
    padding: 0;
    white-space: nowrap;
    background-color: var(--pre-background-color);
    border: 0 solid var(--border2);
    -webkit-border-radius: var(--border-radius-default);
    border-radius: var(--border-radius-default);
    text-shadow: none;
}

pre, pre > code {
    line-height: 1.2;
    color: inherit;
    font-family: "Consolas", "Deja Vu Sans Mono", "Bitstream Vera Sans Mono", monospace;
    font-weight: normal;
}

kbd.keyseq {
    color: var(--dark-gray-color);
}

kbd:not(.keyseq) {
    display: inline-block;
    color: black;
    font-size: 0.75em;
    line-height: 1.4;
    background-color: var(--kdb-background-color);
    border: 1px solid #ccc;
    -webkit-border-radius: 3px;
    border-radius: 3px;
    -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 0 0 2px white inset;
    box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 0 0 2px white inset;
    margin: -0.15em 0.15em 0 0.15em;
    padding: 0.2em 0.6em 0.2em 0.5em;
    vertical-align: middle;
    white-space: nowrap;
}

kbd kbd:first-child {
    margin-left: 0;
}

kbd kbd:last-child {
    margin-right: 0;
}

.menuseq, .menu {
    color: black;
}

p a > code:hover {
    color: var(--link-hover-color);
}

#header, #content, #footnotes, #footer {
    width: 100%;
    margin-left: auto;
    margin-right: auto;
    margin-top: 0;
    margin-bottom: 0;
    max-width: 62.5em;
    *zoom: 1;
    position: relative;
    padding-left: 0.9375em;
    padding-right: 0.9375em;
}

#header:before, #header:after, #content:before, #content:after, #footnotes:before, #footnotes:after, #footer:before, #footer:after {
    content: " ";
    display: table;
}

#header:after, #content:after, #footnotes:after, #footer:after {
    clear: both;
}

#header {
    margin-bottom: 2.5em;
}

#header > h1 {
    color: var(--header-color);
    font-weight: bold;
    border-bottom: 1px solid var(--border2);
    margin-bottom: -28px;
    padding-bottom: 32px;
}

#header span {
    color: var(--accent-secondary-color);
}

#header #revnumber {
    text-transform: capitalize;
}

#header br {
    display: none;
}

#header br + span {
    padding-left: 3px;
}

#header br + span:before {
    content: "\2013 \0020";
}

#header br + span.author {
    padding-left: 0;
}

#header br + span.author:before {
    content: ", ";
}

#toc {
    border-bottom: 1px solid var(--border2);
    padding-bottom: 1.25em;
}

#toc > ul {
    margin-left: 0.25em;
}

#toc ul.sectlevel0 > li > a {
    font-style: italic;
}

#toc ul.sectlevel0 ul.sectlevel1 {
    margin-left: 0;
    margin-top: 0.5em;
    margin-bottom: 0.5em;
}

#toc ul {
    list-style-type: none;
}

#toctitle {
    color: var(--accent-primary-color);
}

@media only screen and (min-width: 1280px) {
    body.toc2 {
        padding-left: 20em;
    }

    #toc.toc2 {
        position: fixed;
        width: 20em;
        left: 0;
        top: 0;
        border-right: 1px solid var(--border2);
        border-bottom: 0;
        z-index: 1000;
        padding: 44px 1em 1em;
        height: 100%;
        overflow: auto;
    }

    #toc.toc2 > ul {
        padding-left: 1em;
    }

    #toc.toc2 #toctitle {
        margin-top: 0;
    }

    #toc.toc2 > ul {
        font-size: .95em;
    }

    #toc.toc2 ul ul {
        margin-left: 0;
        padding-left: 1.25em;
    }

    #toc.toc2 ul.sectlevel0 ul.sectlevel1 {
        padding-left: 0;
        margin-top: 0.5em;
        margin-bottom: 0.5em;
    }

    body.toc2.toc-right {
        padding-left: 0;
        padding-right: 20em;
    }

    body.toc2.toc-right #toc.toc2 {
        border-right: 0;
        border-left: 1px solid var(--border2);
        left: auto;
        right: 0;
    }
}

#content #toc {
    border-style: solid;
    border-width: 1px;
    border-color: var(--toc-border-color);
    margin-bottom: 1.25em;
    padding: 1.25em;
    background: var(--pre-background-color);
    border-width: 0;
    -webkit-border-radius: var(--border-radius-default);
    border-radius: var(--border-radius-default);
}

#content #toc > :first-child {
    margin-top: 0;
}

#content #toc > :last-child {
    margin-bottom: 0;
}

#content #toc a {
    color: var(--gray-color);
    text-decoration: none;
}

#content #toctitle {
    font-weight: bold;
    font-family: ff-meta-web-pro-1, ff-meta-web-pro-2, Arial, "Helvetica Neue", sans-serif;
    font-size: 1em;
    padding-left: 0.125em;
}

#footer {
    max-width: 100%;
    background-color: black;
    padding: 1.25em;
}

#footer-text {
    color: white;
    line-height: 1.35;
}

.sect1 {
    padding-bottom: 1.25em;
}

.sect1 + .sect1 {
    border-top: 1px solid var(--border2);
}

#content h1 > a.anchor, h2 > a.anchor, h3 > a.anchor, #toctitle > a.anchor, .sidebarblock > .content > .title > a.anchor, h4 > a.anchor, h5 > a.anchor, h6 > a.anchor {
    position: absolute;
    width: 1em;
    margin-left: -1em;
    display: block;
    text-decoration: none;
    visibility: hidden;
    text-align: center;
    font-weight: normal;
}

#content h1 > a.anchor:before, h2 > a.anchor:before, h3 > a.anchor:before, #toctitle > a.anchor:before, .sidebarblock > .content > .title > a.anchor:before, h4 > a.anchor:before, h5 > a.anchor:before, h6 > a.anchor:before {
    content: '\00A7';
    font-size: .85em;
    vertical-align: text-top;
    display: block;
    margin-top: 0.05em;
}

#content h1:hover > a.anchor, #content h1 > a.anchor:hover, h2:hover > a.anchor, h2 > a.anchor:hover, h3:hover > a.anchor, #toctitle:hover > a.anchor, .sidebarblock > .content > .title:hover > a.anchor, h3 > a.anchor:hover, #toctitle > a.anchor:hover, .sidebarblock > .content > .title > a.anchor:hover, h4:hover > a.anchor, h4 > a.anchor:hover, h5:hover > a.anchor, h5 > a.anchor:hover, h6:hover > a.anchor, h6 > a.anchor:hover {
    visibility: visible;
}

#content h1 > a.link, h2 > a.link, h3 > a.link, #toctitle > a.link, .sidebarblock > .content > .title > a.link, h4 > a.link, h5 > a.link, h6 > a.link {
    color: var(--accent-primary-color);
    text-decoration: none;
}

#content h1 > a.link:hover, h2 > a.link:hover, h3 > a.link:hover, #toctitle > a.link:hover, .sidebarblock > .content > .title > a.link:hover, h4 > a.link:hover, h5 > a.link:hover, h6 > a.link:hover {
    color: var(--link-hover-color);
}

.imageblock, .literalblock, .listingblock, .verseblock, .videoblock {
    margin-bottom: 1.25em;
}

.admonitionblock td.content > .title, .exampleblock > .title, .imageblock > .title, .videoblock > .title, .listingblock > .title, .literalblock > .title, .openblock > .title, .paragraph > .title, .quoteblock > .title, .sidebarblock > .title, .tableblock > .title, .verseblock > .title, .dlist > .title, .olist > .title, .ulist > .title, .qlist > .title, .hdlist > .title {
    text-align: left;
    font-weight: bold;
}

.tableblock > caption {
    text-align: left;
    font-weight: bold;
    white-space: nowrap;
    overflow: visible;
    max-width: 0;
}

table.tableblock #preamble > .sectionbody > .paragraph:first-of-type p {
    font-size: inherit;
}

.admonitionblock > table {
    border: 0;
    background: none;
    width: 100%;
}

.admonitionblock > table td.icon {
    text-align: center;
    width: 60px;
    padding: 0;
    font-size: 1.5em;
}

.admonitionblock > table td.icon img {
    max-width: none;
}

.admonitionblock > table td.icon .title {
    font-weight: bold;
    text-transform: uppercase;
}

.admonitionblock > table td.content {
    /*padding-left: 1.125em;*/
    /*padding-right: 1.25em;*/
    border-left: 1px solid var(--border2);
    color: var(--accent-secondary-color);
}

.admonitionblock > table td.content > :last-child > :last-child {
    margin-bottom: 0;
}

.exampleblock > .content {
    border-style: solid;
    border-width: 1px;
    border-color: var(--exampleblock-border-color);
    margin-bottom: 1.25em;
    padding: 1.25em;
    background: white;
    -webkit-border-radius: var(--border-radius-default);
    border-radius: var(--border-radius-default);
}

.exampleblock > .content > :first-child {
    margin-top: 0;
}

.exampleblock > .content > :last-child {
    margin-bottom: 0;
}

.exampleblock > .content h1, .exampleblock > .content h2, .exampleblock > .content h3, .exampleblock > .content #toctitle, .sidebarblock.exampleblock > .content > .title, .exampleblock > .content h4, .exampleblock > .content h5, .exampleblock > .content h6, .exampleblock > .content p {
    color: var(--dark-gray-color);
}

.exampleblock > .content h1, .exampleblock > .content h2, .exampleblock > .content h3, .exampleblock > .content #toctitle, .sidebarblock.exampleblock > .content > .title, .exampleblock > .content h4, .exampleblock > .content h5, .exampleblock > .content h6 {
    line-height: 1;
    margin-bottom: 0.625em;
}

.exampleblock > .content h1.subheader, .exampleblock > .content h2.subheader, .exampleblock > .content h3.subheader, .exampleblock > .content .subheader#toctitle, .sidebarblock.exampleblock > .content > .subheader.title, .exampleblock > .content h4.subheader, .exampleblock > .content h5.subheader, .exampleblock > .content h6.subheader {
    line-height: 1.4;
}

.exampleblock.result > .content {
    -webkit-box-shadow: 0 1px 8px var(--toc-border-color);
    box-shadow: 0 1px 8px var(--toc-border-color);
}

.sidebarblock {
    border-style: solid;
    border-width: 1px;
    border-color: var(--toc-border-color);
    margin-bottom: 1.25em;
    padding: 1.25em;
    background: var(--pre-background-color);
    -webkit-border-radius: var(--border-radius-default);
    border-radius: var(--border-radius-default);
}

.sidebarblock > :first-child {
    margin-top: 0;
}

.sidebarblock > :last-child {
    margin-bottom: 0;
}

.sidebarblock h1, .sidebarblock h2, .sidebarblock h3, .sidebarblock #toctitle, .sidebarblock > .content > .title, .sidebarblock h4, .sidebarblock h5, .sidebarblock h6, .sidebarblock p {
    color: var(--dark-gray-color);
}

.sidebarblock h1, .sidebarblock h2, .sidebarblock h3, .sidebarblock #toctitle, .sidebarblock > .content > .title, .sidebarblock h4, .sidebarblock h5, .sidebarblock h6 {
    line-height: 1;
    margin-bottom: 0.625em;
}

.sidebarblock h1.subheader, .sidebarblock h2.subheader, .sidebarblock h3.subheader, .sidebarblock .subheader#toctitle, .sidebarblock > .content > .subheader.title, .sidebarblock h4.subheader, .sidebarblock h5.subheader, .sidebarblock h6.subheader {
    line-height: 1.4;
}

.sidebarblock > .content > .title {
    color: var(--gray-color);
    margin-top: 0;
    line-height: 1.5;
}

.exampleblock > .content > :last-child > :last-child, .exampleblock > .content .olist > ol > li:last-child > :last-child, .exampleblock > .content .ulist > ul > li:last-child > :last-child, .exampleblock > .content .qlist > ol > li:last-child > :last-child, .sidebarblock > .content > :last-child > :last-child, .sidebarblock > .content .olist > ol > li:last-child > :last-child, .sidebarblock > .content .ulist > ul > li:last-child > :last-child, .sidebarblock > .content .qlist > ol > li:last-child > :last-child {
    margin-bottom: 0;
}

.literalblock > .content pre, .listingblock > .content pre {
    background: #eeeeee;
    border-width: 1px;
    border-style: solid;
    border-color: #cccccc;
    -webkit-border-radius: var(--border-radius-default);
    border-radius: var(--border-radius-default);
    padding: 0.5em;
    word-wrap: break-word;
}

.literalblock > .content pre.nowrap, .listingblock > .content pre.nowrap {
    overflow-x: auto;
    white-space: pre;
    word-wrap: normal;
}

.literalblock > .content pre > code, .listingblock > .content pre > code {
    display: block;
}

@media only screen {
    .literalblock > .content pre, .listingblock > .content pre {
        font-size: 0.76em;
    }
}

@media only screen and (min-width: 768px) {
    .literalblock > .content pre, .listingblock > .content pre {
        font-size: 0.855em;
    }
}

@media only screen and (min-width: 1280px) {
    .literalblock > .content pre, .listingblock > .content pre {
        font-size: 0.95em;
    }
}

.listingblock > .content {
    position: relative;
}

.listingblock:hover code[class*=" language-"]:before {
    text-transform: uppercase;
    font-size: 0.9em;
    color: #999;
    position: absolute;
    top: 0.375em;
    right: 0.375em;
}

.listingblock:hover code.asciidoc:before {
    content: "asciidoc";
}

.listingblock:hover code.clojure:before {
    content: "clojure";
}

.listingblock:hover code.css:before {
    content: "css";
}

.listingblock:hover code.groovy:before {
    content: "groovy";
}

.listingblock:hover code.html:before {
    content: "html";
}

.listingblock:hover code.java:before {
    content: "java";
}

.listingblock:hover code.javascript:before {
    content: "javascript";
}

.listingblock:hover code.python:before {
    content: "python";
}

.listingblock:hover code.ruby:before {
    content: "ruby";
}

.listingblock:hover code.scss:before {
    content: "scss";
}

.listingblock:hover code.xml:before {
    content: "xml";
}

.listingblock:hover code.yaml:before {
    content: "yaml";
}

.listingblock.terminal pre .command:before {
    content: attr(data-prompt);
    padding-right: 0.5em;
    color: #999;
}

.listingblock.terminal pre .command:not([data-prompt]):before {
    content: '$';
}

table.pyhltable {
    border: 0;
    margin-bottom: 0;
}

table.pyhltable td {
    vertical-align: top;
    padding-top: 0;
    padding-bottom: 0;
}

table.pyhltable td.code {
    padding-left: .75em;
    padding-right: 0;
}

.highlight.pygments .lineno, table.pyhltable td:not(.code) {
    color: #999;
    padding-left: 0;
    padding-right: .5em;
    border-right: 1px solid var(--border2);
}

.highlight.pygments .lineno {
    display: inline-block;
    margin-right: .25em;
}

table.pyhltable .linenodiv {
    background-color: transparent !important;
    padding-right: 0 !important;
}

.quoteblock {
    margin: 0 0 1.25em;
    padding: 0.5625em 1.25em 0 1.1875em;
    border-left: 1px solid var(--border2);
}

.quoteblock blockquote {
    margin: 0 0 1.25em 0;
    padding: 0 0 0.5625em 0;
    border: 0;
}

.quoteblock blockquote > .paragraph:last-child p {
    margin-bottom: 0;
}

.quoteblock .attribution {
    margin-top: -.25em;
    padding-bottom: 0.5625em;
    font-size: 0.8125em;
    color: var(--block-quote-color);
}

.quoteblock .attribution br {
    display: none;
}

.quoteblock .attribution cite {
    display: block;
    margin-bottom: 0.625em;
}

table thead th, table tfoot th {
    font-weight: bold;
}

table.tableblock.grid-all {
    border-collapse: separate;
    border-spacing: 1px;
    -webkit-border-radius: var(--border-radius-default);
    border-radius: var(--border-radius-default);
    border-top: 0 solid var(--border2);
    border-bottom: 0 solid var(--border2);
}

table.tableblock.frame-topbot, table.tableblock.frame-none {
    border-left: 0;
    border-right: 0;
}

table.tableblock.frame-sides, table.tableblock.frame-none {
    border-top: 0;
    border-bottom: 0;
}

table.tableblock td .paragraph:last-child p, table.tableblock td > p:last-child {
    margin-bottom: 0;
}

th.tableblock.halign-left, td.tableblock.halign-left {
    text-align: left;
}

th.tableblock.halign-right, td.tableblock.halign-right {
    text-align: right;
}

th.tableblock.halign-center, td.tableblock.halign-center {
    text-align: center;
}

th.tableblock.valign-top, td.tableblock.valign-top {
    vertical-align: top;
}

th.tableblock.valign-bottom, td.tableblock.valign-bottom {
    vertical-align: bottom;
}

th.tableblock.valign-middle, td.tableblock.valign-middle {
    vertical-align: middle;
}

p.tableblock.header {
    color: var(--foreground-color);
    font-weight: bold;
}

td > div.verse {
    white-space: pre;
}

ol {
    margin-left: 0.25em;
}

ul li ol {
    margin-left: 0;
}

dl dd {
    margin-left: 1.125em;
}

dl dd:last-child, dl dd:last-child > :last-child {
    margin-bottom: 0;
}

ol > li p, ul > li p, ul dd, ol dd, .olist .olist, .ulist .ulist, .ulist .olist, .olist .ulist {
    margin-bottom: 0.625em;
}

ul.unstyled, ol.unnumbered, ul.checklist, ul.none {
    list-style-type: none;
}

ul.unstyled, ol.unnumbered, ul.checklist {
    margin-left: 0.625em;
}

ul.checklist li > p:first-child > i[class^="icon-check"]:first-child, ul.checklist li > p:first-child > input[type="checkbox"]:first-child {
    margin-right: 0.25em;
}

ul.checklist li > p:first-child > input[type="checkbox"]:first-child {
    position: relative;
    top: 1px;
}

ul.inline {
    margin: 0 auto 0.625em auto;
    margin-left: -1.375em;
    margin-right: 0;
    padding: 0;
    list-style: none;
    overflow: hidden;
}

ul.inline > li {
    list-style: none;
    float: left;
    margin-left: 1.375em;
    display: block;
}

ul.inline > li > * {
    display: block;
}

.unstyled dl dt {
    font-weight: normal;
    font-style: normal;
}

ol.arabic {
    list-style-type: decimal;
}

ol.decimal {
    list-style-type: decimal-leading-zero;
}

ol.loweralpha {
    list-style-type: lower-alpha;
}

ol.upperalpha {
    list-style-type: upper-alpha;
}

ol.lowerroman {
    list-style-type: lower-roman;
}

ol.upperroman {
    list-style-type: upper-roman;
}

ol.lowergreek {
    list-style-type: lower-greek;
}

.hdlist > table, .colist > table {
    border: 0;
    background: none;
}

.hdlist > table > tbody > tr, .colist > table > tbody > tr {
    background: none;
}

td.hdlist1 {
    padding-right: .8em;
    font-weight: bold;
}

td.hdlist1, td.hdlist2 {
    vertical-align: top;
}

.literalblock + .colist, .listingblock + .colist {
    margin-top: -0.5em;
}

.colist > table tr > td:first-of-type {
    padding: 0 .8em;
    line-height: 1;
}

.colist > table tr > td:last-of-type {
    padding: 0.25em 0;
}

.qanda > ol > li > p > em:only-child {
    color: var(--em-color);
}

.thumb, .th {
    line-height: 0;
    display: inline-block;
    border: solid 4px white;
    -webkit-box-shadow: 0 0 0 1px var(--border2);
    box-shadow: 0 0 0 1px var(--border2);
}

.imageblock.left, .imageblock[style*="float: left"] {
    margin: 0.25em 0.625em 1.25em 0;
}

.imageblock.right, .imageblock[style*="float: right"] {
    margin: 0.25em 0 1.25em 0.625em;
}

.imageblock > .title {
    margin-bottom: 0;
}

.imageblock.thumb, .imageblock.th {
    border-width: var(--border-radius-default);
}

.imageblock.thumb > .title, .imageblock.th > .title {
    padding: 0 0.125em;
}

.image.left, .image.right {
    margin-top: 0.25em;
    margin-bottom: 0.25em;
    display: inline-block;
    line-height: 0;
}

.image.left {
    margin-right: 0.625em;
}

.image.right {
    margin-left: 0.625em;
}

a.image {
    text-decoration: none;
}

span.footnote, span.footnoteref {
    vertical-align: super;
    font-size: 0.875em;
}

span.footnote a, span.footnoteref a {
    text-decoration: none;
}

#footnotes {
    padding-top: 0.75em;
    padding-bottom: 0.75em;
    margin-bottom: 0.625em;
}

#footnotes hr {
    width: 20%;
    min-width: 6.25em;
    margin: -.25em 0 .75em 0;
    border-width: 1px 0 0 0;
}

#footnotes .footnote {
    padding: 0 0.375em;
    line-height: 1.3;
    font-size: 0.875em;
    margin-left: 1.2em;
    text-indent: -1.2em;
    margin-bottom: .2em;
}

#footnotes .footnote a:first-of-type {
    font-weight: bold;
    text-decoration: none;
}

#footnotes .footnote:last-of-type {
    margin-bottom: 0;
}

#content #footnotes {
    margin-top: -0.625em;
    margin-bottom: 0;
    padding: 0.75em 0;
}

.gist .file-data > table {
    border: none;
    background: var(--background);
    width: 100%;
    margin-bottom: 0;
}

.gist .file-data > table td.line-data {
    width: 99%;
}

div.unbreakable {
    page-break-inside: avoid;
}

.big {
    font-size: larger;
}

.small {
    font-size: smaller;
}

.underline {
    text-decoration: underline;
}

.overline {
    text-decoration: overline;
}

.line-through {
    text-decoration: line-through;
}

.aqua {
    color: #00bfbf;
}

.aqua-background {
    background-color: #00fafa;
}

.black {
    color: black;
}

.black-background {
    background-color: black;
}

.blue {
    color: #0000bf;
}

.blue-background {
    background-color: #0000fa;
}

.fuchsia {
    color: #bf00bf;
}

.fuchsia-background {
    background-color: #fa00fa;
}

.gray {
    color: #606060;
}

.gray-background {
    background-color: #7d7d7d;
}

.green {
    color: #006000;
}

.green-background {
    background-color: #007d00;
}

.lime {
    color: #00bf00;
}

.lime-background {
    background-color: #00fa00;
}

.maroon {
    color: #600000;
}

.maroon-background {
    background-color: #7d0000;
}

.navy {
    color: #000060;
}

.navy-background {
    background-color: #00007d;
}

.olive {
    color: #606000;
}

.olive-background {
    background-color: #7d7d00;
}

.purple {
    color: #600060;
}

.purple-background {
    background-color: #7d007d;
}

.red {
    color: #bf0000;
}

.red-background {
    background-color: #fa0000;
}

.silver {
    color: #909090;
}

.silver-background {
    background-color: #bcbcbc;
}

.teal {
    color: #006060;
}

.teal-background {
    background-color: #007d7d;
}

.white {
    color: #bfbfbf;
}

.white-background {
    background-color: #fafafa;
}

.yellow {
    color: #bfbf00;
}

.yellow-background {
    background-color: #fafa00;
}

span.icon > [class^="icon-"], span.icon > [class*=" icon-"] {
    cursor: default;
}


.admonitionblock td.icon [class^="icon-"]:before {
    font-size: 2.5em;
    text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
    cursor: default;
}

.admonitionblock td.icon .icon-note:before {
    content: "\f05a";
    color: var(--accent-primary-color);
}

.admonitionblock td.icon .icon-tip:before {
    content: "\f0eb";
    /*text-shadow: 1px 1px 2px var(--accent-primary-color);*/
    color: var(--accent-primary-color);
}

.fa {
    font-family: "FontAwesome", "Helvetica Neue", sans-serif;
}

.admonitionblock td.icon .icon-warning:before {
    content: "\f071";
    color: #bf6900;
}

.admonitionblock td.icon .icon-caution:before {
    content: "\f06d";
    color: #bf3400;
}

.admonitionblock td.icon .icon-important:before {
    content: "\f06a";
    color: #bf0000;
}

.conum {
    display: inline-block;
    color: white !important;
    background-color: black;
    -webkit-border-radius: 100px;
    border-radius: 100px;
    text-align: center;
    width: 20px;
    height: 20px;
    font-size: 12px;
    font-weight: bold;
    line-height: 20px;
    font-family: Arial, sans-serif;
    font-style: normal;
    position: relative;
    top: -2px;
    letter-spacing: -1px;
}

.conum * {
    color: white !important;
}

.conum + b {
    display: none;
}

.conum:after {
    content: attr(data-value);
}

.conum:not([data-value]):empty {
    display: none;
}

h4 {
    color: var(--gray-color);
}

.literalblock > .content > pre, .listingblock > .content > pre {
    -webkit-border-radius: var(--border-radius-default);
    border-radius: var(--border-radius-default);
    margin-left: 0.5em;
    margin-right: 0.5em;
}

.admonitionblock {
    margin-left: .5em;
    margin-right: .5em;
}

.admonitionblock > table {
    border: 1px solid var(--accent-primary-color);
    border-left-width: 4px;
    background-color: var(--admotion-background-color);
    border-collapse: separate;
    -webkit-border-radius: var(--border-radius-default);
    border-radius: var(--border-radius-default);
}

.admonitionblock > table td.icon {
    padding-top: .5em;
    padding-bottom: .5em;
}

.admonitionblock > table td.content {
    padding: .5em .2em;
    color: black;
    font-size: .9em;
    border-left: none;
}

.sidebarblock {
    background-color: var(--sidebar-background-color);
    border-color: #ccc;
}

.sidebarblock > .content > .title {
    color: var(--link-color-default);
}

table.tableblock.grid-all {
    border-collapse: collapse;
    -webkit-border-radius: 0;
    border-radius: 0;
}

table.tableblock.grid-all th.tableblock, table.tableblock.grid-all td.tableblock {
    border-bottom: 1px solid #aaa;
}

#footer {
    background-color: var(--accent-primary-color);
    padding: 2em;
}

#footer-text {
    color: #eee;
    font-size: 0.8em;
    text-align: center;
}
</style>
<style>
pre.rouge table td { padding: 5px; }
pre.rouge table pre { margin: 0; }
pre.rouge, pre.rouge .w {
  color: #24292f;
  background-color: #f6f8fa;
}
pre.rouge .k, pre.rouge .kd, pre.rouge .kn, pre.rouge .kp, pre.rouge .kr, pre.rouge .kt, pre.rouge .kv {
  color: #cf222e;
}
pre.rouge .gr {
  color: #f6f8fa;
}
pre.rouge .gd {
  color: #82071e;
  background-color: #ffebe9;
}
pre.rouge .nb {
  color: #953800;
}
pre.rouge .nc {
  color: #953800;
}
pre.rouge .no {
  color: #953800;
}
pre.rouge .nn {
  color: #953800;
}
pre.rouge .sr {
  color: #116329;
}
pre.rouge .na {
  color: #116329;
}
pre.rouge .nt {
  color: #116329;
}
pre.rouge .gi {
  color: #116329;
  background-color: #dafbe1;
}
pre.rouge .ges {
  font-weight: bold;
  font-style: italic;
}
pre.rouge .kc {
  color: #0550ae;
}
pre.rouge .l, pre.rouge .ld, pre.rouge .m, pre.rouge .mb, pre.rouge .mf, pre.rouge .mh, pre.rouge .mi, pre.rouge .il, pre.rouge .mo, pre.rouge .mx {
  color: #0550ae;
}
pre.rouge .sb {
  color: #0550ae;
}
pre.rouge .bp {
  color: #0550ae;
}
pre.rouge .ne {
  color: #0550ae;
}
pre.rouge .nl {
  color: #0550ae;
}
pre.rouge .py {
  color: #0550ae;
}
pre.rouge .nv, pre.rouge .vc, pre.rouge .vg, pre.rouge .vi, pre.rouge .vm {
  color: #0550ae;
}
pre.rouge .o, pre.rouge .ow {
  color: #0550ae;
}
pre.rouge .gh {
  color: #0550ae;
  font-weight: bold;
}
pre.rouge .gu {
  color: #0550ae;
  font-weight: bold;
}
pre.rouge .s, pre.rouge .sa, pre.rouge .sc, pre.rouge .dl, pre.rouge .sd, pre.rouge .s2, pre.rouge .se, pre.rouge .sh, pre.rouge .sx, pre.rouge .s1, pre.rouge .ss {
  color: #0a3069;
}
pre.rouge .nd {
  color: #8250df;
}
pre.rouge .nf, pre.rouge .fm {
  color: #8250df;
}
pre.rouge .err {
  color: #f6f8fa;
  background-color: #82071e;
}
pre.rouge .c, pre.rouge .ch, pre.rouge .cd, pre.rouge .cm, pre.rouge .cp, pre.rouge .cpf, pre.rouge .c1, pre.rouge .cs {
  color: #6e7781;
}
pre.rouge .gl {
  color: #6e7781;
}
pre.rouge .gt {
  color: #6e7781;
}
pre.rouge .ni {
  color: #24292f;
}
pre.rouge .si {
  color: #24292f;
}
pre.rouge .ge {
  color: #24292f;
  font-style: italic;
}
pre.rouge .gs {
  color: #24292f;
  font-weight: bold;
}
</style>
</head>
<body class="article toc2 toc-left">
<div id="header">
<h1>Basic ViewLocator Sample</h1>
<div id="toc" class="toc2">
<div id="toctitle">Table of Contents</div>
<ul class="sectlevel1">
<li><a href="#_before_we_start">Before we start</a>
<ul class="sectlevel2">
<li><a href="#_what_is_a_viewlocator">What is a ViewLocator?</a></li>
<li><a href="#_where_do_i_find_the_viewlocator_instance">Where do I find the ViewLocator instance?</a></li>
<li><a href="#_can_i_have_more_than_one_viewlocator">Can I have more than one ViewLocator?</a></li>
</ul>
</li>
<li><a href="#_the_solution_usage_of_viewlocator">The Solution : Usage of ViewLocator</a>
<ul class="sectlevel2">
<li><a href="#_step_1_create_a_new_project">Step 1: Create a new Project</a></li>
<li><a href="#base-class">Step 2: Add a base class for the Page-ViewModels</a></li>
<li><a href="#_step_3_create_your_pageviewmodels">Step 3: Create your PageViewModels</a></li>
<li><a href="#_step_4_create_the_page_views">Step 4: Create the Page-Views</a></li>
<li><a href="#_step_5_prepare_the_mainwindowviewmodel">Step 5: Prepare the MainWindowViewModel</a></li>
<li><a href="#_step_6_setup_the_mainwindow">Step 6: Setup the MainWindow</a></li>
<li><a href="#_step_6_see_it_in_action">Step 6: See it in action</a></li>
</ul>
</li>
<li><a href="#_related">Related</a></li>
</ul>
</div>
</div>
<div id="content">
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>This example will show you how to use a <code>ViewLocator</code> in order to change the contents of your UI.</p>
</div>
<!-- toc disabled -->
<h3 id="_difficulty" class="discrete">Difficulty</h3>
<div class="paragraph">
<p>🐔 Normal 🐔</p>
</div>
<h3 id="_buzz_words" class="discrete">Buzz-Words</h3>
<div class="paragraph">
<p>ViewLocator, Routing, Wizard, Navigation, Page, MVVM</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_before_we_start">Before we start</h2>
<div class="sectionbody">
<div class="paragraph">
<p>You should already know what the <code>MVVM</code> Pattern is and what <code>DataTemplates</code> in Avalonia do. If these are new to you, please study the samples provided here:
* <a href="https://github.com/AvaloniaUI/Avalonia.Samples#mvvm-samples">[MVVM-Samples]</a>
* <a href="https://github.com/AvaloniaUI/Avalonia.Samples#%EF%B8%8F-datatemplate-samples">[DataTemplate-Samples]</a></p>
</div>
<div class="sect2">
<h3 id="_what_is_a_viewlocator">What is a ViewLocator?</h3>
<div class="paragraph">
<p>A <code>ViewLocator</code> is a class that helps your App to select the correct visual representation of a given <code>ViewModel</code>. In Avalonia this class normally implements the <code>IDataTemplate</code>-interface, so it can be seen as a <a href="https://github.com/AvaloniaUI/Avalonia.Samples/tree/main/src/Avalonia.Samples/DataTemplates/IDataTemplateSample">[custom <code>DataTemplate</code>]</a>.</p>
</div>
<div class="paragraph">
<p>We can add a class called <code>ViewLocator</code> which can be used to create a new instance of a view for the given data object. In this sample we are using reflection to get the needed views. You can also use different approaches such as a <code>switch</code>-statement or a source generator.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
If you have created your projects using the Avalonia version 0.10.x, you might have already noticed that a file called <code>ViewLocator.cs</code> was created. In Avalonia 11.0 or later you need to implement this class on your own if needed.
</td>
</tr>
</table>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="cs"><span class="k">using</span> <span class="nn">Avalonia.Controls</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">Avalonia.Controls.Templates</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">MyNameSpace.ViewModels</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">System</span><span class="p">;</span>

<span class="k">namespace</span> <span class="nn">MyNameSpace</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">ViewLocator</span> <span class="p">:</span> <span class="n">IDataTemplate</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="n">Control</span> <span class="nf">Build</span><span class="p">(</span><span class="kt">object</span><span class="p">?</span> <span class="n">data</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">data</span> <span class="k">is</span> <span class="k">null</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="k">return</span> <span class="k">new</span> <span class="n">TextBlock</span> <span class="p">{</span> <span class="n">Text</span> <span class="p">=</span> <span class="s">"data was null"</span> <span class="p">};</span>
            <span class="p">}</span>

            <span class="kt">var</span> <span class="n">name</span> <span class="p">=</span> <span class="n">data</span><span class="p">.</span><span class="nf">GetType</span><span class="p">().</span><span class="n">FullName</span><span class="p">!.</span><span class="nf">Replace</span><span class="p">(</span><span class="s">"ViewModel"</span><span class="p">,</span> <span class="s">"View"</span><span class="p">);</span>
            <span class="kt">var</span> <span class="n">type</span> <span class="p">=</span> <span class="n">Type</span><span class="p">.</span><span class="nf">GetType</span><span class="p">(</span><span class="n">name</span><span class="p">);</span>

            <span class="k">if</span> <span class="p">(</span><span class="n">type</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="k">return</span> <span class="p">(</span><span class="n">Control</span><span class="p">)</span><span class="n">Activator</span><span class="p">.</span><span class="nf">CreateInstance</span><span class="p">(</span><span class="n">type</span><span class="p">)!;</span>
            <span class="p">}</span>
            <span class="k">else</span>
            <span class="p">{</span>
                <span class="k">return</span> <span class="k">new</span> <span class="n">TextBlock</span> <span class="p">{</span> <span class="n">Text</span> <span class="p">=</span> <span class="s">"Not Found: "</span> <span class="p">+</span> <span class="n">name</span> <span class="p">};</span>
            <span class="p">}</span>
        <span class="p">}</span>

        <span class="k">public</span> <span class="kt">bool</span> <span class="nf">Match</span><span class="p">(</span><span class="kt">object</span><span class="p">?</span> <span class="n">data</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">return</span> <span class="n">data</span> <span class="k">is</span> <span class="n">ViewModelBase</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Let&#8217;s see what the ViewLocator does:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">bool Match(object? data)</dt>
<dd>
<p>This function will return <code>true</code> if the given object derives from <code>ViewModelBase</code>. If your <code>ViewModels</code> have a different base-class, feel free to change this line to whatever you need.</p>
</dd>
<dt class="hdlist1">Control Build(object? data)</dt>
<dd>
<p>This function uses <a href="https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/reflection">[<code>Reflection</code>]</a> to create a new instance of the <code>View</code> representing the given <code>ViewModel</code>. First of all the full name of the ViewModel is extracted, for example:</p>
<div class="paragraph">
<p><code>MyAppsNameSpace.ViewModels.MyViewModel</code></p>
</div>
<div class="paragraph">
<p>Now all occurrences of <code>ViewModel</code> will be replaced by <code>View</code>:</p>
</div>
<div class="paragraph">
<p><code>MyAppsNameSpace.Views.MyView</code></p>
</div>
<div class="paragraph">
<p>In the next step the <code>ViewLocator</code> tries to get a <code>Type</code> of object with the given name. If it finds such a <code>Type</code>, it will create and return a new instance of the given <code>Type</code>. If it didn&#8217;t find a matching <code>Type</code>, it returns a <code>TextBlock</code> with a not found message.</p>
</div>
</dd>
</dl>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
By convention the <code>ViewModel</code> must be within the <code>ViewModels</code>-folder and have "ViewModel" inside it&#8217;s name. The <code>View</code> on the other hand must be in the <code>Views</code>-folder and have <code>View</code> in it&#8217;s name. If you don&#8217;t like this convention, feel free to change it to your needs.
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="_where_do_i_find_the_viewlocator_instance">Where do I find the ViewLocator instance?</h3>
<div class="paragraph">
<p>We will add a new instance of the <code>ViewLocator</code> inside <code>App.DataTemplates</code> in the file <code>App.axaml</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="xml"><span class="c">&lt;!-- remember to add: xmlns:local="using:MyNameSpace" --&gt;</span>
<span class="nt">&lt;Application.DataTemplates&gt;</span>
    <span class="nt">&lt;local:ViewLocator/&gt;</span>
<span class="nt">&lt;/Application.DataTemplates&gt;</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>If no other <code>DataTemplate</code> matches your object, this instance of the <code>ViewLocator</code> will be called.</p>
</div>
</div>
<div class="sect2">
<h3 id="_can_i_have_more_than_one_viewlocator">Can I have more than one ViewLocator?</h3>
<div class="paragraph">
<p>Sometimes your <code>ViewModels</code> and <code>Views</code> may be stored in a shared library. If that is the case, you can add several <code>ViewLocator</code> classes. Just remember to initiate each one in <code>App.DataTemplates</code>.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_solution_usage_of_viewlocator">The Solution : Usage of ViewLocator</h2>
<div class="sectionbody">
<div class="paragraph">
<p>In this sample we will create a simple Wizard that consists of three pages. The user can navigate forward and backward.</p>
</div>
<div class="sect2">
<h3 id="_step_1_create_a_new_project">Step 1: Create a new Project</h3>
<div class="paragraph">
<p>Create a new project using the "Avalonia MVVM Template".</p>
</div>
</div>
<div class="sect2">
<h3 id="base-class">Step 2: Add a base class for the Page-ViewModels</h3>
<div class="paragraph">
<p>We want to allow or disallow navigation based on the state of the current user input. For example, the user should not be able to go to the next page until all required fields are filled successfully. To achieve this we can either create a new <code>base-class</code> or an <code>interface</code>. In this sample we will create an <a href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/abstract">[<code>abstract</code>]</a> <code>base-class</code> which itself derives from <code>ViewModelBase</code>. The properties itself are also marked as <code>abstract</code> which means we have to override them in any <code>class</code> that inherits our <code>base-class</code>.</p>
</div>
<div class="paragraph">
<p>In the folder <code>ViewModels</code> create the file <code>PageViewModelBase.cs</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="cs"><span class="c1">/// &lt;summary&gt;</span>
<span class="c1">/// An abstract class for enabling page navigation.</span>
<span class="c1">/// &lt;/summary&gt;</span>
<span class="k">public</span> <span class="k">abstract</span> <span class="k">class</span> <span class="nc">PageViewModelBase</span> <span class="p">:</span> <span class="n">ViewModelBase</span>
<span class="p">{</span>
    <span class="c1">/// &lt;summary&gt;</span>
    <span class="c1">/// Gets if the user can navigate to the next page</span>
    <span class="c1">/// &lt;/summary&gt;</span>
    <span class="k">public</span> <span class="k">abstract</span> <span class="kt">bool</span> <span class="n">CanNavigateNext</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">protected</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

    <span class="c1">/// &lt;summary&gt;</span>
    <span class="c1">/// Gets if the user can navigate to the previous page</span>
    <span class="c1">/// &lt;/summary&gt;</span>
    <span class="k">public</span> <span class="k">abstract</span> <span class="kt">bool</span> <span class="n">CanNavigatePrevious</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">protected</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span></code></pre>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
the <code>protected</code>-modifier let&#8217;s us implement a setter that is not public accessible, but can be overridden in derived classes. <a href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/protected">[Microsoft Docs]</a>
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="_step_3_create_your_pageviewmodels">Step 3: Create your PageViewModels</h3>
<div class="paragraph">
<p>Let&#8217;s create a <code>ViewModel</code> for each Wizard page we need. Each <code>PageViewModel</code> must implement the above created <a href="#base-class">base-class</a>.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
You need to <code>override</code> all the <code>abstract</code> properties of our <code>base-class</code>. <a href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/override">[Microsoft Docs]</a>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_firstpageviewmodel">FirstPageViewModel</h4>
<div class="paragraph">
<p>The fist page will be our welcome page. It has a <code>Title</code> and a <code>Message</code>. The user can go to the next page in any case, but there is no page to go back to. So we don&#8217;t need to implement the <code>setter</code>. To indicate that we throw a <a href="https://learn.microsoft.com/en-us/dotnet/api/system.notsupportedexception">[<code>NotSupportedException</code>]</a>.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="cs"><span class="c1">/// &lt;summary&gt;</span>
<span class="c1">///  This is our ViewModel for the first page</span>
<span class="c1">/// &lt;/summary&gt;</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">FirstPageViewModel</span> <span class="p">:</span> <span class="n">PageViewModelBase</span>
<span class="p">{</span>
    <span class="c1">/// &lt;summary&gt;</span>
    <span class="c1">/// The Title of this page</span>
    <span class="c1">/// &lt;/summary&gt;</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Title</span> <span class="p">=&gt;</span> <span class="s">"Welcome to our Wizard-Sample."</span><span class="p">;</span>

    <span class="c1">/// &lt;summary&gt;</span>
    <span class="c1">/// The content of this page</span>
    <span class="c1">/// &lt;/summary&gt;</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Message</span> <span class="p">=&gt;</span> <span class="s">"Press \"Next\" to register yourself."</span><span class="p">;</span>

    <span class="c1">// This is our first page, so we can navigate to the next page in any case</span>
    <span class="k">public</span> <span class="k">override</span> <span class="kt">bool</span> <span class="n">CanNavigateNext</span>
    <span class="p">{</span>
        <span class="k">get</span> <span class="p">=&gt;</span> <span class="k">true</span><span class="p">;</span>
        <span class="k">protected</span> <span class="k">set</span> <span class="p">=&gt;</span> <span class="k">throw</span> <span class="k">new</span> <span class="nf">NotSupportedException</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="c1">// You cannot go back from this page</span>
    <span class="k">public</span> <span class="k">override</span> <span class="kt">bool</span> <span class="n">CanNavigatePrevious</span>
    <span class="p">{</span>
        <span class="k">get</span> <span class="p">=&gt;</span> <span class="k">false</span><span class="p">;</span>
        <span class="k">protected</span> <span class="k">set</span> <span class="p">=&gt;</span> <span class="k">throw</span> <span class="k">new</span> <span class="nf">NotSupportedException</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_secondpageviewmodel">SecondPageViewModel</h4>
<div class="paragraph">
<p>This page will have two input fields called <code>MailAddress</code> and <code>Password</code>. Inside the constructor of this class we will listen to changes of these properties and set <code>CanNavigateNext</code> to <code>true</code> if both properties matches the requirements.</p>
</div>
<div class="paragraph">
<p>The requirements are:
- <code>MailAddress</code> may not be empty
- <code>Password</code> may not be empty
- <code>MailAddress</code> must be a valid E-Mail-Address and thus contain an <code>@</code></p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="cs"><span class="c1">/// &lt;summary&gt;</span>
<span class="c1">///  This is our ViewModel for the second page</span>
<span class="c1">/// &lt;/summary&gt;</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">SecondPageViewModel</span> <span class="p">:</span> <span class="n">PageViewModelBase</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">SecondPageViewModel</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="c1">// Listen to changes of MailAddress and Password and update CanNavigateNext accordingly</span>
        <span class="k">this</span><span class="p">.</span><span class="nf">WhenAnyValue</span><span class="p">(</span><span class="n">x</span> <span class="p">=&gt;</span> <span class="n">x</span><span class="p">.</span><span class="n">MailAddress</span><span class="p">,</span> <span class="n">x</span> <span class="p">=&gt;</span> <span class="n">x</span><span class="p">.</span><span class="n">Password</span><span class="p">)</span>
            <span class="p">.</span><span class="nf">Subscribe</span><span class="p">(</span><span class="n">_</span> <span class="p">=&gt;</span> <span class="nf">UpdateCanNavigateNext</span><span class="p">());</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="kt">string</span><span class="p">?</span> <span class="n">_MailAddress</span><span class="p">;</span>

    <span class="c1">/// &lt;summary&gt;</span>
    <span class="c1">/// The E-Mail of the user. This field is required</span>
    <span class="c1">/// &lt;/summary&gt;</span>
    <span class="p">[</span><span class="n">Required</span><span class="p">]</span>
    <span class="p">[</span><span class="n">EmailAddress</span><span class="p">]</span>
    <span class="k">public</span> <span class="kt">string</span><span class="p">?</span> <span class="n">MailAddress</span>
    <span class="p">{</span>
        <span class="k">get</span> <span class="p">{</span> <span class="k">return</span> <span class="n">_MailAddress</span><span class="p">;</span> <span class="p">}</span>
        <span class="k">set</span> <span class="p">{</span> <span class="k">this</span><span class="p">.</span><span class="nf">RaiseAndSetIfChanged</span><span class="p">(</span><span class="k">ref</span> <span class="n">_MailAddress</span><span class="p">,</span> <span class="k">value</span><span class="p">);</span> <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="kt">string</span><span class="p">?</span> <span class="n">_Password</span><span class="p">;</span>

    <span class="c1">/// &lt;summary&gt;</span>
    <span class="c1">/// The password of the user. This field is required.</span>
    <span class="c1">/// &lt;/summary&gt;</span>
    <span class="p">[</span><span class="n">Required</span><span class="p">]</span>
    <span class="k">public</span> <span class="kt">string</span><span class="p">?</span> <span class="n">Password</span>
    <span class="p">{</span>
        <span class="k">get</span> <span class="p">{</span> <span class="k">return</span> <span class="n">_Password</span><span class="p">;</span> <span class="p">}</span>
        <span class="k">set</span> <span class="p">{</span> <span class="k">this</span><span class="p">.</span><span class="nf">RaiseAndSetIfChanged</span><span class="p">(</span><span class="k">ref</span> <span class="n">_Password</span><span class="p">,</span> <span class="k">value</span><span class="p">);</span> <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="kt">bool</span> <span class="n">_CanNavigateNext</span><span class="p">;</span>

    <span class="c1">// For this page the user can only go to the next page if all fields are valid. So we need a private setter.</span>
    <span class="k">public</span> <span class="k">override</span> <span class="kt">bool</span> <span class="n">CanNavigateNext</span>
    <span class="p">{</span>
        <span class="k">get</span> <span class="p">{</span> <span class="k">return</span> <span class="n">_CanNavigateNext</span><span class="p">;</span> <span class="p">}</span>
        <span class="k">protected</span> <span class="k">set</span> <span class="p">{</span> <span class="k">this</span><span class="p">.</span><span class="nf">RaiseAndSetIfChanged</span><span class="p">(</span><span class="k">ref</span> <span class="n">_CanNavigateNext</span><span class="p">,</span> <span class="k">value</span><span class="p">);</span> <span class="p">}</span>
    <span class="p">}</span>

    <span class="c1">// We allow navigate back in any case</span>
    <span class="k">public</span> <span class="k">override</span> <span class="kt">bool</span> <span class="n">CanNavigatePrevious</span>
    <span class="p">{</span>
        <span class="k">get</span> <span class="p">=&gt;</span> <span class="k">true</span><span class="p">;</span>
        <span class="k">protected</span> <span class="k">set</span> <span class="p">=&gt;</span> <span class="k">throw</span> <span class="k">new</span> <span class="nf">NotSupportedException</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="c1">// Update CanNavigateNext. Allow next page if E-Mail and Password are valid</span>
    <span class="k">private</span> <span class="k">void</span> <span class="nf">UpdateCanNavigateNext</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">CanNavigateNext</span> <span class="p">=</span>
                <span class="p">!</span><span class="kt">string</span><span class="p">.</span><span class="nf">IsNullOrEmpty</span><span class="p">(</span><span class="n">_MailAddress</span><span class="p">)</span>
            <span class="p">&amp;&amp;</span> <span class="n">_MailAddress</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="s">"@"</span><span class="p">)</span>
            <span class="p">&amp;&amp;</span> <span class="p">!</span><span class="kt">string</span><span class="p">.</span><span class="nf">IsNullOrEmpty</span><span class="p">(</span><span class="n">_Password</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre>
</div>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
We use <code>DataAnnotations</code> to validate the user input inside the UI. This is totally optional. You can read more about in the <a href="https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.validationattribute">[Microsoft Docs]</a>.
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_thirdpageviewmodel">ThirdPageViewModel</h4>
<div class="paragraph">
<p>This page will only show a <code>Message</code> with the content "Done". The user can still navigate back, but not to the next page as there is no next page.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="cs"><span class="c1">/// &lt;summary&gt;</span>
<span class="c1">///  This is our ViewModel for the third page</span>
<span class="c1">/// &lt;/summary&gt;</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">ThirdPageViewModel</span> <span class="p">:</span> <span class="n">PageViewModelBase</span>
<span class="p">{</span>
    <span class="c1">// The message to display</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Message</span> <span class="p">=&gt;</span> <span class="s">"Done"</span><span class="p">;</span>

    <span class="c1">// This is the last page, so we cannot navigate next in our sample.</span>
    <span class="k">public</span> <span class="k">override</span> <span class="kt">bool</span> <span class="n">CanNavigateNext</span>
    <span class="p">{</span>
        <span class="k">get</span> <span class="p">=&gt;</span> <span class="k">false</span><span class="p">;</span>
        <span class="k">protected</span> <span class="k">set</span> <span class="p">=&gt;</span> <span class="k">throw</span> <span class="k">new</span> <span class="nf">NotSupportedException</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="c1">// We navigate back form this page in any case</span>
    <span class="k">public</span> <span class="k">override</span> <span class="kt">bool</span> <span class="n">CanNavigatePrevious</span>
    <span class="p">{</span>
        <span class="k">get</span> <span class="p">=&gt;</span> <span class="k">true</span><span class="p">;</span>
        <span class="k">protected</span> <span class="k">set</span> <span class="p">=&gt;</span> <span class="k">throw</span> <span class="k">new</span> <span class="nf">NotSupportedException</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_step_4_create_the_page_views">Step 4: Create the Page-Views</h3>
<div class="paragraph">
<p>Now we will create an <a href="https://docs.avaloniaui.net/docs/controls/usercontrol">[<code>UserControl</code>]</a> for each page.</p>
</div>
<div class="sect3">
<h4 id="_firstpageview">FirstPageView</h4>
<div class="paragraph">
<p>This is the first page. We just add two <code>TextBlocks</code> which shows the <code>Title</code> and <code>Message</code>.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="xml"><span class="nt">&lt;UserControl</span> <span class="na">x:Class=</span><span class="s">"BasicViewLocatorSample.Views.FirstPageView"</span>
             <span class="na">xmlns=</span><span class="s">"https://github.com/avaloniaui"</span>
             <span class="na">xmlns:x=</span><span class="s">"http://schemas.microsoft.com/winfx/2006/xaml"</span>
             <span class="na">xmlns:d=</span><span class="s">"http://schemas.microsoft.com/expression/blend/2008"</span>
             <span class="na">xmlns:mc=</span><span class="s">"http://schemas.openxmlformats.org/markup-compatibility/2006"</span>
             <span class="na">xmlns:vm=</span><span class="s">"using:BasicViewLocatorSample.ViewModels"</span>
             <span class="na">d:DesignHeight=</span><span class="s">"450"</span>
             <span class="na">d:DesignWidth=</span><span class="s">"800"</span>
             <span class="na">x:CompileBindings=</span><span class="s">"True"</span>
             <span class="na">x:DataType=</span><span class="s">"vm:FirstPageViewModel"</span>
             <span class="na">mc:Ignorable=</span><span class="s">"d"</span><span class="nt">&gt;</span>
	<span class="nt">&lt;Design.DataContext&gt;</span>
		<span class="nt">&lt;vm:FirstPageViewModel</span> <span class="nt">/&gt;</span>
	<span class="nt">&lt;/Design.DataContext&gt;</span>

	<span class="nt">&lt;StackPanel</span> <span class="na">VerticalAlignment=</span><span class="s">"Center"</span> <span class="na">Spacing=</span><span class="s">"5"</span><span class="nt">&gt;</span>
		<span class="nt">&lt;TextBlock</span> <span class="na">VerticalAlignment=</span><span class="s">"Center"</span>
			       <span class="na">TextAlignment=</span><span class="s">"Center"</span>
			       <span class="na">FontSize=</span><span class="s">"16"</span>
			       <span class="na">FontWeight=</span><span class="s">"SemiBold"</span>
                   <span class="na">Text=</span><span class="s">"{Binding Title}"</span>
                   <span class="na">TextWrapping=</span><span class="s">"Wrap"</span> <span class="nt">/&gt;</span>
		<span class="nt">&lt;TextBlock</span> <span class="na">VerticalAlignment=</span><span class="s">"Center"</span>
			       <span class="na">TextAlignment=</span><span class="s">"Center"</span>
			       <span class="na">FontSize=</span><span class="s">"16"</span>
                   <span class="na">Text=</span><span class="s">"{Binding Message}"</span>
                   <span class="na">TextWrapping=</span><span class="s">"Wrap"</span> <span class="nt">/&gt;</span>
	<span class="nt">&lt;/StackPanel&gt;</span>
<span class="nt">&lt;/UserControl&gt;</span></code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_secondpageview">SecondPageView</h4>
<div class="paragraph">
<p>This page will contain two <code>TextBoxes</code> for the input of <code>MailAddress</code> and <code>Password</code>.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
If you set any <code>PasswordChar</code> to any <code>TextBox</code> you will get a password input field.
</td>
</tr>
</table>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="xml"><span class="nt">&lt;UserControl</span> <span class="na">x:Class=</span><span class="s">"BasicViewLocatorSample.Views.SecondPageView"</span>
             <span class="na">xmlns=</span><span class="s">"https://github.com/avaloniaui"</span>
             <span class="na">xmlns:x=</span><span class="s">"http://schemas.microsoft.com/winfx/2006/xaml"</span>
             <span class="na">xmlns:d=</span><span class="s">"http://schemas.microsoft.com/expression/blend/2008"</span>
             <span class="na">xmlns:mc=</span><span class="s">"http://schemas.openxmlformats.org/markup-compatibility/2006"</span>
             <span class="na">xmlns:vm=</span><span class="s">"using:BasicViewLocatorSample.ViewModels"</span>
             <span class="na">d:DesignHeight=</span><span class="s">"450"</span>
             <span class="na">d:DesignWidth=</span><span class="s">"800"</span>
             <span class="na">x:CompileBindings=</span><span class="s">"True"</span>
             <span class="na">x:DataType=</span><span class="s">"vm:SecondPageViewModel"</span>
             <span class="na">mc:Ignorable=</span><span class="s">"d"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;Design.DataContext&gt;</span>
        <span class="nt">&lt;vm:SecondPageViewModel</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;/Design.DataContext&gt;</span>

    <span class="nt">&lt;StackPanel</span> <span class="na">VerticalAlignment=</span><span class="s">"Center"</span> <span class="na">Spacing=</span><span class="s">"5"</span> <span class="na">MaxWidth=</span><span class="s">"350"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;TextBlock</span> <span class="na">VerticalAlignment=</span><span class="s">"Center"</span>
                   <span class="na">FontSize=</span><span class="s">"16"</span>
                   <span class="na">FontWeight=</span><span class="s">"SemiBold"</span>
                   <span class="na">Text=</span><span class="s">"Enter your Credentials"</span>
                   <span class="na">TextAlignment=</span><span class="s">"Center"</span>
                   <span class="na">TextWrapping=</span><span class="s">"Wrap"</span> <span class="nt">/&gt;</span>
        <span class="nt">&lt;TextBox</span> <span class="na">VerticalAlignment=</span><span class="s">"Center"</span>
                 <span class="na">FontSize=</span><span class="s">"16"</span>
                 <span class="na">Text=</span><span class="s">"{Binding MailAddress}"</span>
                 <span class="na">Watermark=</span><span class="s">"E-Mail Address"</span>
				 <span class="na">UseFloatingWatermark=</span><span class="s">"True"</span><span class="nt">/&gt;</span>
		<span class="nt">&lt;TextBox</span> <span class="na">VerticalAlignment=</span><span class="s">"Center"</span>
                 <span class="na">FontSize=</span><span class="s">"16"</span>
				 <span class="na">PasswordChar=</span><span class="s">"$"</span>
                 <span class="na">Text=</span><span class="s">"{Binding Password}"</span>
                 <span class="na">Watermark=</span><span class="s">"Password"</span>
				 <span class="na">UseFloatingWatermark=</span><span class="s">"True"</span><span class="nt">/&gt;</span>
    <span class="nt">&lt;/StackPanel&gt;</span>
<span class="nt">&lt;/UserControl&gt;</span></code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_thirdpageview">ThirdPageView</h4>
<div class="paragraph">
<p>We will not implement this page yet. This way you can see what happens if a specific page is not found. Feel free to add this page later on your own.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_step_5_prepare_the_mainwindowviewmodel">Step 5: Prepare the MainWindowViewModel</h3>
<div class="paragraph">
<p>Now we need create the navigation logic inside the file <code>ViewModels ► MainWindowViewModel.cs</code>. We will add four things:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">Pages</dt>
<dd>
<p>An <code>Array</code> of <code>PageViewModels</code> that stores all possible pages</p>
</dd>
<dt class="hdlist1">CurrentPage</dt>
<dd>
<p>Gets or sets the current <code>PageViewModel</code></p>
</dd>
<dt class="hdlist1">NavigateNextCommand</dt>
<dd>
<p>A <code>Command</code> that will navigate to the next page</p>
</dd>
<dt class="hdlist1">NavigatePreviousCommand</dt>
<dd>
<p>A <code>Command</code> that will navigate to the previous page</p>
</dd>
</dl>
</div>
<div class="paragraph">
<p>As you will see in the constructor we will use <code>WhenAnyValue</code> to activate or deactivate the <code>Commands</code>, depending if the <code>CurrentPage</code> can navigate in the considered direction.</p>
</div>
<div class="paragraph">
<p>Putting all together, the <code>MainWindowViewModel</code> looks now like this:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="cs"><span class="k">public</span> <span class="k">class</span> <span class="nc">MainWindowViewModel</span> <span class="p">:</span> <span class="n">ViewModelBase</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">MainWindowViewModel</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="c1">// Set current page to first on start up</span>
        <span class="n">_CurrentPage</span> <span class="p">=</span> <span class="n">Pages</span><span class="p">[</span><span class="m">0</span><span class="p">];</span>

        <span class="c1">// Create Observables which will activate to deactivate our commands based on CurrentPage state</span>
        <span class="kt">var</span> <span class="n">canNavNext</span> <span class="p">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">WhenAnyValue</span><span class="p">(</span><span class="n">x</span> <span class="p">=&gt;</span> <span class="n">x</span><span class="p">.</span><span class="n">CurrentPage</span><span class="p">.</span><span class="n">CanNavigateNext</span><span class="p">);</span>
        <span class="kt">var</span> <span class="n">canNavPrev</span> <span class="p">=</span> <span class="k">this</span><span class="p">.</span><span class="nf">WhenAnyValue</span><span class="p">(</span><span class="n">x</span> <span class="p">=&gt;</span> <span class="n">x</span><span class="p">.</span><span class="n">CurrentPage</span><span class="p">.</span><span class="n">CanNavigatePrevious</span><span class="p">);</span>

        <span class="n">NavigateNextCommand</span> <span class="p">=</span> <span class="n">ReactiveCommand</span><span class="p">.</span><span class="nf">Create</span><span class="p">(</span><span class="n">NavigateNext</span><span class="p">,</span> <span class="n">canNavNext</span><span class="p">);</span>
        <span class="n">NavigatePreviousCommand</span> <span class="p">=</span> <span class="n">ReactiveCommand</span><span class="p">.</span><span class="nf">Create</span><span class="p">(</span><span class="n">NavigatePrevious</span><span class="p">,</span> <span class="n">canNavPrev</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="c1">// A read.only array of possible pages</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">PageViewModelBase</span><span class="p">[]</span> <span class="n">Pages</span> <span class="p">=</span>
    <span class="p">{</span>
        <span class="k">new</span> <span class="nf">FirstPageViewModel</span><span class="p">(),</span>
        <span class="k">new</span> <span class="nf">SecondPageViewModel</span><span class="p">(),</span>
        <span class="k">new</span> <span class="nf">ThirdPageViewModel</span><span class="p">()</span>
    <span class="p">};</span>

    <span class="c1">// The default is the first page</span>
    <span class="k">private</span> <span class="n">PageViewModelBase</span> <span class="n">_CurrentPage</span><span class="p">;</span>

    <span class="c1">/// &lt;summary&gt;</span>
    <span class="c1">/// Gets the current page. The property is read-only</span>
    <span class="c1">/// &lt;/summary&gt;</span>
    <span class="k">public</span> <span class="n">PageViewModelBase</span> <span class="n">CurrentPage</span>
    <span class="p">{</span>
        <span class="k">get</span> <span class="p">{</span> <span class="k">return</span> <span class="n">_CurrentPage</span><span class="p">;</span> <span class="p">}</span>
        <span class="k">private</span> <span class="k">set</span> <span class="p">{</span> <span class="k">this</span><span class="p">.</span><span class="nf">RaiseAndSetIfChanged</span><span class="p">(</span><span class="k">ref</span> <span class="n">_CurrentPage</span><span class="p">,</span> <span class="k">value</span><span class="p">);</span> <span class="p">}</span>
    <span class="p">}</span>

    <span class="c1">/// &lt;summary&gt;</span>
    <span class="c1">/// Gets a command that navigates to the next page</span>
    <span class="c1">/// &lt;/summary&gt;</span>
    <span class="k">public</span> <span class="n">ICommand</span> <span class="n">NavigateNextCommand</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>

    <span class="k">private</span> <span class="k">void</span> <span class="nf">NavigateNext</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="c1">// get the current index and add 1</span>
        <span class="kt">var</span> <span class="n">index</span> <span class="p">=</span> <span class="n">Pages</span><span class="p">.</span><span class="nf">IndexOf</span><span class="p">(</span><span class="n">CurrentPage</span><span class="p">)</span> <span class="p">+</span> <span class="m">1</span><span class="p">;</span>

        <span class="c1">//  /!\ Be aware that we have no check if the index is valid. You may want to add it on your own. /!\</span>
        <span class="n">CurrentPage</span> <span class="p">=</span> <span class="n">Pages</span><span class="p">[</span><span class="n">index</span><span class="p">];</span>
    <span class="p">}</span>

    <span class="c1">/// &lt;summary&gt;</span>
    <span class="c1">/// Gets a command that navigates to the previous page</span>
    <span class="c1">/// &lt;/summary&gt;</span>
    <span class="k">public</span> <span class="n">ICommand</span> <span class="n">NavigatePreviousCommand</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>

    <span class="k">private</span> <span class="k">void</span> <span class="nf">NavigatePrevious</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="c1">// get the current index and subtract 1</span>
        <span class="kt">var</span> <span class="n">index</span> <span class="p">=</span> <span class="n">Pages</span><span class="p">.</span><span class="nf">IndexOf</span><span class="p">(</span><span class="n">CurrentPage</span><span class="p">)</span> <span class="p">-</span> <span class="m">1</span><span class="p">;</span>

        <span class="c1">//  /!\ Be aware that we have no check if the index is valid. You may want to add it on your own. /!\</span>
        <span class="n">CurrentPage</span> <span class="p">=</span> <span class="n">Pages</span><span class="p">[</span><span class="n">index</span><span class="p">];</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_step_6_setup_the_mainwindow">Step 6: Setup the MainWindow</h3>
<div class="paragraph">
<p>Now it&#8217;s time to setup the file <code>Views ► MainWindow.axaml</code>. We will add <code>Grid</code> containing two <code>Buttons</code> as well as a <a href="https://docs.avaloniaui.net/docs/controls/transitioningcontentcontrol">[<code>TransitioningContentControl</code>]</a>.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
You can use also any other <code>ContentControl</code>, but the <code>TransitioningContentControl</code> will display a nice transition when the user navigates.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Note how we can just use <code>Content="{Binding CurrentPage}"</code>. The magic will happen in the <code>ViewLocator</code>.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="xml"><span class="nt">&lt;Window</span> <span class="na">x:Class=</span><span class="s">"BasicViewLocatorSample.Views.MainWindow"</span>
        <span class="na">xmlns=</span><span class="s">"https://github.com/avaloniaui"</span>
        <span class="na">xmlns:x=</span><span class="s">"http://schemas.microsoft.com/winfx/2006/xaml"</span>
        <span class="na">xmlns:d=</span><span class="s">"http://schemas.microsoft.com/expression/blend/2008"</span>
        <span class="na">xmlns:mc=</span><span class="s">"http://schemas.openxmlformats.org/markup-compatibility/2006"</span>
        <span class="na">xmlns:vm=</span><span class="s">"using:BasicViewLocatorSample.ViewModels"</span>
        <span class="na">Title=</span><span class="s">"BasicViewLocatorSample"</span>
        <span class="na">d:DesignHeight=</span><span class="s">"450"</span>
        <span class="na">d:DesignWidth=</span><span class="s">"800"</span>
        <span class="na">x:CompileBindings=</span><span class="s">"True"</span>
        <span class="na">x:DataType=</span><span class="s">"vm:MainWindowViewModel"</span>
        <span class="na">Icon=</span><span class="s">"/Assets/avalonia-logo.ico"</span>
        <span class="na">mc:Ignorable=</span><span class="s">"d"</span><span class="nt">&gt;</span>

    <span class="nt">&lt;Design.DataContext&gt;</span>
        <span class="nt">&lt;vm:MainWindowViewModel</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;/Design.DataContext&gt;</span>

    <span class="nt">&lt;Grid</span> <span class="na">RowDefinitions=</span><span class="s">"*,Auto"</span> <span class="na">Margin=</span><span class="s">"10"</span><span class="nt">&gt;</span>
        <span class="nt">&lt;TransitioningContentControl</span> <span class="na">Content=</span><span class="s">"{Binding CurrentPage}"</span> <span class="nt">/&gt;</span>

        <span class="nt">&lt;StackPanel</span> <span class="na">Grid.Row=</span><span class="s">"1"</span> <span class="na">Orientation=</span><span class="s">"Horizontal"</span> <span class="na">Spacing=</span><span class="s">"5"</span>
					<span class="na">HorizontalAlignment=</span><span class="s">"Right"</span><span class="nt">&gt;</span>
            <span class="nt">&lt;Button</span> <span class="na">Command=</span><span class="s">"{Binding NavigatePreviousCommand}"</span> <span class="na">Content=</span><span class="s">"Back"</span> <span class="nt">/&gt;</span>
            <span class="nt">&lt;Button</span> <span class="na">Command=</span><span class="s">"{Binding NavigateNextCommand}"</span> <span class="na">Content=</span><span class="s">"Next"</span> <span class="nt">/&gt;</span>
        <span class="nt">&lt;/StackPanel&gt;</span>
    <span class="nt">&lt;/Grid&gt;</span>
<span class="nt">&lt;/Window&gt;</span></code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_step_6_see_it_in_action">Step 6: See it in action</h3>
<div class="paragraph">
<p>In your IDE hit [Run] or [Debug] and see the result:</p>
</div>
<div class="imageblock">
<div class="content">
<img src="_docs/result.png" alt="Result">
</div>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
Do you see the content of the last page? This happens because we didn&#8217;t define a <code>View</code> for it and also we didn&#8217;t define any <code>DataTemplate</code> for it.
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_related">Related</h2>
<div class="sectionbody">
<div class="paragraph">
<p>You can also use any third-party library which supports advanced routing, for example:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">ReactiveUI</dt>
<dd>
<div class="ulist">
<ul>
<li>
<p><a href="https://www.reactiveui.net/docs/handbook/routing/" class="bare">https://www.reactiveui.net/docs/handbook/routing/</a></p>
</li>
<li>
<p><a href="https://docs.avaloniaui.net/guides/deep-dives/reactiveui/routing" class="bare">https://docs.avaloniaui.net/guides/deep-dives/reactiveui/routing</a></p>
</li>
</ul>
</div>
</dd>
<dt class="hdlist1">Prism</dt>
<dd>
<div class="ulist">
<ul>
<li>
<p><a href="https://prismlibrary.com/docs/viewmodel-locator.html" class="bare">https://prismlibrary.com/docs/viewmodel-locator.html</a></p>
</li>
<li>
<p><a href="https://docs.avaloniaui.net/guides/deep-dives/reactiveui/routing" class="bare">https://docs.avaloniaui.net/guides/deep-dives/reactiveui/routing</a></p>
</li>
</ul>
</div>
</dd>
</dl>
</div>
</div>
</div>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2025-11-06 19:42:36 UTC
</div>
</div>
</body>
</html>